﻿using System;
using System.Globalization;
using System.Xml.Linq;

namespace Director.StockSharp.Transaq.Native
{
	static class Extensions
	{
		private const string DATETimeFormat = "dd.MM.yyyy HH:mm:ss";

		public static char POINT_CHAR = '.';

		public static string ToMyString(this DateTime date)
		{
			return date.ToString(DATETimeFormat);
		}

		public static string ToMyString(this bool b)
		{
			return b.ToString().ToLower();
		}

		public static DateTime ToDate(this string s, DateTime now, bool isUtc =  true)
		{
			if (s == "0")
				return now.Date;

			DateTime date;
			TimeSpan time;

			if (DateTime.TryParseExact(s, "dd.MM.yyyy", null, DateTimeStyles.None, out date))
			{
				date = date + now.TimeOfDay;
			}
			else if (DateTime.TryParseExact(s, "dd.MM.yyyy HH:mm:ss", null, DateTimeStyles.None, out date))
			{
			}
			else if (TimeSpan.TryParseExact(s, "g", null, out time))
			{
				date = now.Date + time;
			}
			else
			{
				date = DateTime.ParseExact(s, "dd.MM.yyyy HH:mm:ss.fff", CultureInfo.InvariantCulture);
			}
			
			return isUtc ? FromUTC(date) : date;
		}

		private static DateTime FromUTC(DateTime date)
		{
			return date.AddHours(3);
		}

		public static bool FromYesNo(this string s)
		{
			return s.CompareIgnoreCase("yes") || s.CompareIgnoreCase("y");
		}

		public static string ToYesNo(this bool b)
		{
			return b ? "YES" : "NO";
		}

		public static T? GetElementValueNullable<T>(this XElement elem, string name, Func<DateTime> getNow = null)
			where T : struct
		{
			if (elem == null)
				throw new ArgumentNullException("elem");

			elem = elem.Element(name);

			if (elem == null)
				return null;

			var value = elem.Value;

			if (string.IsNullOrEmpty(value))
				return null;

			if (typeof(T) == typeof(decimal))
				return value.To<decimal>().To<T>();

			if (typeof(T) == typeof(DateTime))
			{
				if (getNow == null)
					throw new ArgumentNullException("getNow");

				return value.ToDate(getNow()).To<T>();
			}

			return value.To<T>();
		}

		public static T To<T>(this object s) //where T : struct
		{
			if (typeof (T).IsEnum)
			{
				return (T)Enum.Parse(typeof(T),(string)s);
			}
			return (T)Convert.ChangeType(s, typeof(T),CultureInfo.InvariantCulture);
		}

		public static T GetAttributeValue<T>(this XElement elem, string name, T defaultFalue = default(T))
			where T : struct
		{
			if (elem == null)
				throw new ArgumentNullException("elem");

			foreach (var attribute in elem.Attributes())
			{
				if (attribute.Name == name)
				{
					var value = attribute.Value;

					if (string.IsNullOrEmpty(value))
					{
						return defaultFalue;
					}

					return typeof(T) == typeof(decimal) ? value.To<decimal>().To<T>() : value.To<T>();
				}
			}
			return defaultFalue;
		}

		public static bool IsEmpty(this string s)
		{
			return string.IsNullOrEmpty(s);
		}

		public static string GetAttributeValue(this XElement elem, string name, string defaultFalue = null)
		{
			if (elem == null)
				throw new ArgumentNullException("elem");

			foreach (var attribute in elem.Attributes())
			{
				if (attribute.Name == name)
				{
					return attribute.Value.IsEmpty() ? defaultFalue : attribute.Value;
				}
			}
			return defaultFalue;
		}

		public static string GetElementValue(this XElement elem, string name, string defaultFalue = null, bool throwIfNotExists = true)
		{
			if (elem == null)
				throw new ArgumentNullException("elem");

			elem = elem.Element(name);

			if (elem == null)
			{
				if (throwIfNotExists)
				{
					throw new Exception("Элемент " + name + " не найден");
				}
				return defaultFalue;
			}
			return elem.Value.IsEmpty() ? defaultFalue : elem.Value;
		}

		public static T GetElementValue<T>(this XElement elem, string name, Func<DateTime> getNow = null, bool throwIfNotExists = true)
			where T : struct
		{
			if (elem == null)
				throw new ArgumentNullException("elem");

			elem = elem.Element(name);

			if (elem == null)
			{
				if (throwIfNotExists)
				{
					throw new Exception("Элемент " + name + " не найден");
				}
				return default(T);
			}

			var value = elem.Value;

			if (string.IsNullOrEmpty(value))
			{
				throw new Exception("Значение элемента " + name + " пусто");
			}

			if (typeof(T) == typeof(decimal))
				return value.To<decimal>().To<T>();

			if (typeof(T) == typeof(DateTime))
			{
				if (getNow == null)
					throw new ArgumentNullException("getNow");

				return value.ToDate(getNow()).To<T>();
			}

			return value.To<T>();
		}

		//public static Unit GetElementValueToUnit(this XElement elem, string name)
		//{
		//	if (elem == null)
		//		throw new ArgumentNullException("elem");

		//	elem = elem.Element(name);

		//	return elem == null ? null : elem.Value.IsEmpty() ? null : elem.Value.ToUnit();
		//}

		public static bool CompareIgnoreCase(this string str1, string str2)
		{
			return string.Compare(str1, str2, StringComparison.InvariantCultureIgnoreCase)==0;
		}
	}
}